﻿using System;
using System.Diagnostics;
using System.Threading;
using System.Timers;
using Emgu.CV;
using Emgu.CV.Structure;
using NIPO.Data;
using NIPO.Plugins;
using NIPO.Util;

namespace NIPOCvPlugins.FileInputPlugin
{
    public class VideoFileInputPlugin : InputPlugin
    {
        private Capture _inputFile;
        private FileInputConfiguration _config = new FileInputConfiguration();
        private int _remainingFrames;
        private double _fps;
        private System.Timers.Timer _timer;

        #region Overrides of Plugin

        protected override void Initialize()
        {
            _inputFile = new Capture(_config.FilePath);
            _inputFile.QueryFrame();
            int numFrames = (int)_inputFile.GetCaptureProperty(Emgu.CV.CvEnum.CAP_PROP.CV_CAP_PROP_FRAME_COUNT) - 1;
            Log.WriteDebugFormat("File has {0} frames", numFrames);
            if (numFrames == 0)
                throw new ArgumentException("File contains no Video Frames");
            _remainingFrames = numFrames;
            _fps = _inputFile.GetCaptureProperty(Emgu.CV.CvEnum.CAP_PROP.CV_CAP_PROP_FPS);
            Log.WriteDebugFormat("Original file fps: {0}", _fps);
            Log.WriteDebugFormat("Video is {0}x{1}", _inputFile.GetCaptureProperty(Emgu.CV.CvEnum.CAP_PROP.CV_CAP_PROP_FRAME_WIDTH), _inputFile.GetCaptureProperty(Emgu.CV.CvEnum.CAP_PROP.CV_CAP_PROP_FRAME_HEIGHT));
        }

        public override void Dispose()
        {
            _inputFile.Dispose();
        }


        public override PluginConfiguration ConfigurationObject
        {
            get { return _config; }
            set { _config = value as FileInputConfiguration; }
        }

        public override bool IsConfigured
        {
            get { return !string.IsNullOrEmpty(_config.FilePath); }
        }

        public override void Reset()
        {
            _inputFile.Dispose();
            _inputFile = new Capture(_config.FilePath);
        }

        #endregion

        #region Overrides of InputPlugin

        public override void Run()
        {
            if (_config.SynchronizeToFPS)
            {
                _timer = new System.Timers.Timer(1000 / _fps) { AutoReset = true };
                _timer.Elapsed += delegate(object o, ElapsedEventArgs e) { if (!GrabFrame() || Abort) _timer.Stop(); };
                _timer.Start();
            }
            else
            {
                Stopwatch sw = new Stopwatch();
                sw.Start();
                while (!Abort && GrabFrame())
                {
                }
                sw.Stop();
                Log.WriteInfoFormat("Reading input file finished. Elapsed time: {0}", sw.Elapsed.ToString());
            }
        }

        #endregion


        private bool GrabFrame()
        {
            try
            {

                if (_remainingFrames > 0)
                {
                    Image<Bgr, byte> image;
                    lock (this)
                    {
                        image = _inputFile.QuerySmallFrame();
                    }

                    RaiseNewData(new GenericDTO<Image<Bgr, byte>>(image, "EMGU/Image<Bgr, byte>", image.Bytes.Length,
                                                                  DateTime.Now));
                    Interlocked.Decrement(ref _remainingFrames);
                    return true;
                }
                return false;
            }
            catch (Exception ex)
            {
                Log.WriteErrorFormat("Exception at frame {0}: {1}", _remainingFrames, ex.Message);
                return false;
            }
        }
    }
}
